﻿using System;
using System.Data.Entity;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using mtg_trader.Database;
using mtg_trader.Database.DbSets;

namespace mtg_trader.GUI
{
    public partial class FrmMain : Form
    {
        public FrmMain()
        {
            InitializeComponent();
        }

        private void btnReadAndGenerate_Click(object sender, EventArgs e)
        {

            txtLog.AppendText("Test");
            
            //if (!Directory)

            var streamReader = new StreamReader("C:\\sets.in");

            string lineToProcess = string.Empty;

            while (lineToProcess != "Terminate")
            {
                lineToProcess = streamReader.ReadLine();
                if (string.IsNullOrEmpty(lineToProcess)) continue;
                string[] data = lineToProcess.Split(',');
                if (data.Length <= 2) continue;
                var set = new Set
                    {
                        MagicCardsInfoUri = data[0],
                        Name = data[1],
                        Abbreviation = data[2].ToUpper()
                    };
                using (var context = new MtgContext())
                {
                    if (context.Sets.Count(s => s.Abbreviation == set.Abbreviation) != 0) continue;
                    context.Sets.Add(set);
                    context.SaveChanges();
                }
            }
        }

        private void btnFindNumberOfCardsInSets_Click(object sender, EventArgs e)
        {
            using (var context = new MtgContext())
            {
                DbSet<Set> sets = context.Sets;

                foreach (Set set in sets)
                {
                    string currentUri = set.MagicCardsInfoUri;

                    using (var webClient = new WebClient())
                    {
                        string result = webClient.DownloadString(@"http://magiccards.info" + currentUri)
                                                 .Replace("\n", string.Empty);
                        int startIndex = result.IndexOf(" cards", StringComparison.InvariantCulture);
                        try
                        {
                            result = result.Substring(0, startIndex);
                            result =
                                result.Substring(result.LastIndexOf('>') + 1,
                                                 result.Length - (result.LastIndexOf('>') + 1)).Trim();
                        }
                        catch
                        {
                            result = "1";
                        }
                        Debug.WriteLine(result);
                        set.Size = Convert.ToInt32(result);
                    }
                }
                context.SaveChanges();
            }

            MessageBox.Show("Done.");
        }

        private void btnSpawnCardsToDatabase_Click(object sender, EventArgs e)
        {
            using (var context = new MtgContext())
            {
                DbSet<Set> sets = context.Sets;

                bool tempBool = true;

                foreach (Set set in sets)
                {
                    string currentUri = set.MagicCardsInfoUri;

                    if (!tempBool) continue;

                    using (var webClient = new WebClient())
                    {
                        webClient.Encoding = Encoding.UTF8;
                        string result = webClient.DownloadString(@"http://magiccards.info" + currentUri)
                                                 .Replace("\n", string.Empty);
                        int noStart = result.IndexOf("Card name", StringComparison.InvariantCulture);
                        int trStart = result.LastIndexOf("<tr>", noStart, StringComparison.InvariantCulture);
                        trStart = result.IndexOf("<tr ", trStart, StringComparison.InvariantCulture);
                        for (int i = 0; i < set.Size; i++)
                        {
                            string tempCard = result.Substring(trStart,
                                                               (result.IndexOf("</tr>", trStart,
                                                                               StringComparison.InvariantCulture) +
                                                                "</tr>".Length) - trStart);
                            Card card = ParseCard(tempCard, set.Abbreviation);
                            if (set.Cards.All(c => c.Id != card.Id))
                            {
                                Debug.WriteLine("Card Name: {0} -- {1}", card.Name, card.Number);
                                set.Cards.Add(card);
                            }
                            trStart = result.IndexOf("<tr ", trStart + 1, StringComparison.InvariantCulture);
                        }
                    }
                }
                context.SaveChanges();
            }
        }

        private Card ParseCard(string cardstring, string abbreviation)
        {
            cardstring = cardstring.Replace(",", "^^^");
            cardstring = cardstring.Replace("<tr class=\"even\">    <td align=\"right\">", string.Empty);
            cardstring = cardstring.Replace("<tr class=\"odd\">    <td align=\"right\">", string.Empty);
            cardstring = cardstring.Replace("</td>    <td><a href=\"", ",");
            cardstring = cardstring.Replace("\">", ",");
            cardstring = cardstring.Replace("</a></td>    <td>", ",");
            cardstring = cardstring.Replace("</td>    <td>", ",");
            cardstring = cardstring.Replace("<img src=\"", ",");
            cardstring = cardstring.Replace("\" alt=\"English\" width=\"16\" height=\"11\" class=\"flag2, ", ",");
            cardstring = cardstring.Replace("</td>  </tr>", string.Empty);
            cardstring = cardstring.Replace(",,", ",");

            string[] details = cardstring.Split(',');
            int number = 0;
            string letter = string.Empty;

            try
            {
                number = Convert.ToInt32(details[0]);
            }
            catch (Exception)
            {
                number = Convert.ToInt32(details[0].Substring(0, details[0].Length - 1));
                letter = details[0].Substring(details[0].Length - 1);
            }

            for (int i = 0; i < details.Length; i++)
            {
                details[i] = details[i].Replace("^^^", ",");
            }

            string loyalty = ParseLoyalty(details[3]);
            string[] powerAndToughness = ParsePowerAndToughness(details[3]);
            string types = ParseTypes(details[3]);

            if (details.Length == 8)
            {
                return new Card
                    {
                        Number = number,
                        MagicCardsInfoUri = details[1],
                        Name = details[2],
                        CardRarity = GetRarity(details[4]),
                        Artist = details[5],
                        Id = string.Format("{0}-{1}", abbreviation, details[0]),
                        Letter = letter,
                        Loyalty = loyalty,
                        Power = powerAndToughness[0],
                        Toughness = powerAndToughness[1],
                        Types = types
                    };
            }

            return new Card
                {
                    Number = number,
                    MagicCardsInfoUri = details[1],
                    Name = details[2],
                    ManaCost = details[4],
                    CardRarity = GetRarity(details[5]),
                    Artist = details[6],
                    Id = string.Format("{0}-{1}", abbreviation, details[0]),
                    Letter = letter,
                    Loyalty = loyalty,
                    Power = powerAndToughness[0],
                    Toughness = powerAndToughness[1],
                    Types = types
                };
        }

        private string ParseTypes(string typeString)
        {
            if (typeString.Contains("Loyalty:"))
            {
                int loyaltyPos = typeString.IndexOf('(') - 1;
                return typeString.Substring(0, loyaltyPos);
            }
            else if (typeString.Contains("/"))
            {
                int lastSpacePos = typeString.LastIndexOf(' ');
                return typeString.Substring(0, lastSpacePos);
            }
            return typeString;
        }

        private string[] ParsePowerAndToughness(string typeString)
        {
            string[] powerAndToughness = typeString.Split('/');
            if (powerAndToughness.Length == 1) return new string[] { null, null };
            powerAndToughness[0] = powerAndToughness[0].Substring(powerAndToughness[0].LastIndexOf(' ') + 1);
            return powerAndToughness;
        }

        private string ParseLoyalty(string typeString)
        {
            int loyaltyPos = typeString.IndexOf("Loyalty: ", StringComparison.InvariantCulture);
            if (loyaltyPos > 0)
            {
                loyaltyPos = loyaltyPos + ("Loyalty: ").Length;
                string substring = typeString.Substring(loyaltyPos);
                return substring.Trim().TrimEnd(new[] { ')' });
            }
            return null;
        }

        public Rarity GetRarity(string rarity)
        {
            switch (rarity)
            {
                case "Common":
                case "Common (C1)":
                case "Common (C2)":
                case "Common (C3)":
                case "Common (C4)":
                case "Common (C5)":
                case "Common (U1)":
                case "Common (U3)":
                    return Rarity.Common;
                case "Uncommon":
                case "Uncommon (C1)":
                case "Uncommon (U1)":
                case "Uncommon (U2)":
                case "Uncommon (U3)":
                case "Uncommon (U4)":
                    return Rarity.Uncommon;
                case "Rare":
                case "Rare (R1)":
                case "Rare (U1)":
                case "Rare (U2)":
                case "Rare (C3)":
                    return Rarity.Rare;
                case "Mythic Rare":
                    return Rarity.MythicRare;
                case "Land":
                case "Land (C11)":
                    return Rarity.BasicLand;
                case "Special":
                    return Rarity.Special;
                default:
                    return Rarity.Unknown;
            }
        }

        private void btnGetCardDetails_Click(object sender, EventArgs e)
        {
            DisableButtons();
            
            txtLog.AppendText("Beginning 'Get Card Detail'");
            lblCurrentAction.Text = @"Executing: Get Card Details";

            using (var context = new MtgContext())
            {
                var cardCount = context.Cards.Count();
                prgAction.Maximum = cardCount;
            }
            prgAction.Value = 0;
            var getCardDetailsTask = Task.Factory.StartNew(GetCardDetails) ;

        }

        private void GetCardDetails()
        {

            var stopwatch = new Stopwatch();
            stopwatch.Start();

            using (var context = new MtgContext())
            {
                var cards = context.Cards;

                foreach (var card in cards)
                {
                    var uri = string.Format("http://magiccards.info" + card.MagicCardsInfoUri);
                    var fileName = string.Format("C:\\MtgCards\\{0}", card.Id);

                    var tempCard = ProcessCard(card, UrlDownloader.GetHtml(uri, fileName));

                    prgAction.Invoke(new Action(delegate {
                            prgAction.Value = prgAction.Value + 1;
                        }));

                    card.Artist = tempCard.Artist;
                    card.CardRarity = tempCard.CardRarity;
                    card.Description = tempCard.Description;
                    card.ErrataTypes = tempCard.ErrataTypes;
                    card.Flavor = tempCard.Flavor;
                    card.HighPrice = tempCard.HighPrice;
                    card.Letter = tempCard.Letter;
                    card.Loyalty = tempCard.Loyalty;
                    card.Number = tempCard.Number;
                    card.Types = tempCard.Types;

                }

                context.SaveChanges();

            }
            txtLog.Invoke(new Action(() => txtLog.AppendText(string.Format("Completed 'Get Card Detail' in {0} seconds", stopwatch.ElapsedMilliseconds / 1000))));

            Invoke(new Action(EnableButtons));

        }

        private void EnableButtons()
        {
            var buttons = Controls.OfType<Button>().ToList();

            foreach (var button in buttons)
            {
                button.Enabled = true;
            }

            lblCurrentAction.Text = string.Empty;
            prgAction.Maximum = 100;
            prgAction.Value = 0;

        }

        private void DisableButtons()
        {
            var buttons = Controls.OfType<Button>().ToList();

            foreach (var button in buttons)
            {
                button.Enabled = false;
            }
        }

        private Card ProcessCard(Card card, string unparsedCard)
        {
            int namePos = unparsedCard.IndexOf(card.Name, StringComparison.InvariantCulture);
            int paragraphPos = unparsedCard.IndexOf("<p>", StringComparison.InvariantCulture) + ("<p>".Length);
            string detailsLine = unparsedCard.Substring(paragraphPos,
                                                     unparsedCard.IndexOf("</p>", paragraphPos,
                                                                          StringComparison.InvariantCulture) -
                                                     paragraphPos);
            var details = detailsLine.Split(',');

            for (var i = 0; i < details.Length; i++)
            {
                details[i] = details[i].Replace("\n", string.Empty).Trim();
            }

            if (details[0].Contains("Basic Land") || details[0] == "Land")
            {
                card.ErrataTypes = details[0];
                return card;
            }

            card.ErrataTypes = ParseTypes(details[0]);
            card.Loyalty = ParseLoyalty(details[0]);
            var powerAndToughness = ParsePowerAndToughness(details[0]);
            card.Power = powerAndToughness[0];
            card.Toughness = powerAndToughness[1];

            if (details.Length != 2 && details.Length != 1) Debug.WriteLine("Card: {0}, Split to {1}", card.Name, details.Length);

            var ctextPos = unparsedCard.IndexOf("<p class=\"ctext\"><b>", StringComparison.InvariantCulture) + ("<p class=\"ctext\"><b>").Length;
            var descriptionText = unparsedCard.Substring(ctextPos,
                                                         unparsedCard.IndexOf("</b>", ctextPos,
                                                                              StringComparison.InvariantCulture) -
                                                         ctextPos).Replace("<br><br>", "\n");

            card.Description = descriptionText;

            ctextPos = unparsedCard.IndexOf("<p><i>", ctextPos, StringComparison.InvariantCulture) + ("<p><i>").Length;
            var flavorText = unparsedCard.Substring(ctextPos,
                                                    unparsedCard.IndexOf("</i>", StringComparison.InvariantCulture) -
                                                    ctextPos).Replace("<br>", "\n");
            if (string.IsNullOrEmpty(flavorText)) flavorText = null;

            card.Flavor = flavorText;

            return card;
        }

        private void FrmMain_KeyDown(object sender, KeyEventArgs e)
        {

            if (e.KeyCode == Keys.Escape)
            {
                Application.Exit();
            }

        }
    }

}